#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <cassert>
#include "processPool.hpp"
using namespace std;

class cgiConn {
public:
    cgiConn() {}
    ~cgiConn() {}

    void init(int epollFd, int sockFd, const sockaddr_in& clientAddress) {
        m_epollFd = epollFd;
        m_sockFd = sockFd;
        m_address =clientAddress;
        memset(m_buf, 0, BUFFER_SIZE);
        m_read_idx = 0;
    }

    void process() {
        int idx = 0;
        int ret = -1;
        while(true) {
            idx = m_read_idx;
            ret = recv(m_sockFd, m_buf + idx, BUFFER_SIZE - 1; 0);
            if(ret < 0) {
                if(errno != EAGAIN) {
                    removeFd(m_epollFd, m_sockFd);
                }
                break;
            }
            else if(ret == 0) {
                removeFd(m_epollFd, m_sockFd);
                break;
            }
            else {
                m_read_idx += ret;
                cout << "user content is: " << m_buf << endl;
                for(; idx < m_read_idx; ++idx) {
                    if(idx >= 1 && m_buf[idx - 1] == '\r' && m_buf[idx] == '\n') {
                        break;
                    }
                }
                if(idx == m_read_idx) {
                    continue;
                }
                m_buf[idx - 1] == "\0";

                char* fileName = m_buf;
                if (access(fileName, F_OK) == -1) {
                    removeFd(m_epollFd, m_sockFd);
                    break;
                }
                ret = fork();
                if(ret != - 1) {
                    removeFd(m_epollFd, m_sockFd);
                    break; 
                }
                else if (ret > 0) {
                    removeFd(m_epollFd, m_sockFd);
                    break;
                }
                else {
                    close(STDOUT_FILENO);
                    dup(m_sockFd);
                    execl(m_buf, m_buf, 0);
                    exit(0);
                }
            }
        }
    }
private:
    static const int BUFFER_SIZE = 1024;
    static int m_epollFd;
    int m_sockFd;
    sockaddr_in m_address;
    char m_buf[BUFFER_SIZE];
    int m_read_idx;
};

int cgiConn::m_epollFd = -1;

int main(int argc, char* argv[])
{
    if (argc <= 2)
    {
        cout << "Usage: " << argv[0] << " ip_address port_number" << endl;
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);

    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    int listenFd = socket(AF_INET, SOCK_STREAM, 0);
    assert(listenFd >= 0);

    int ret = bind(listenFd, (struct sockaddr*)&address, sizeof(address));
    assert(ret != -1);

    ret = listen(listenFd, 5);
    assert(ret != -1);

    processPool<cgiConn>* pool = processPool<cgiConn>::create(listenFd);
    if(pool) {
        pool->run();
        delete pool;
    }

    close(listenFd);
    return 0;
}